package com.qianda.qdminiapp.service.order;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.qianda.qdminiapp.common.constant.CommonConstant;
import com.qianda.qdminiapp.common.future.CommandFuture;
import com.qianda.qdminiapp.common.future.SendData;
import com.qianda.qdminiapp.common.rabbitmq.MsgProducer;
import com.qianda.qdminiapp.common.util.DateUtils;
import com.qianda.qdminiapp.common.util.HttpsUtil;
import com.qianda.qdminiapp.common.util.RandomUtil;
import com.qianda.qdminiapp.config.CompanyProperties;
import com.qianda.qdminiapp.dao.account.QqdAccountTradeDao;
import com.qianda.qdminiapp.dao.device.DeviceDao;
import com.qianda.qdminiapp.dao.device.QqdDeviceDao;
import com.qianda.qdminiapp.dao.device.QqdStoreDao;
import com.qianda.qdminiapp.dao.order.OrderDao;
import com.qianda.qdminiapp.dao.order.QqdOrderInfoDao;
import com.qianda.qdminiapp.dao.order.QqdOrderTowelDao;
import com.qianda.qdminiapp.dao.personmanage.QqdCompanyDao;
import com.qianda.qdminiapp.dao.user.QqdUserDao;
import com.qianda.qdminiapp.dao.user.UserDao;
import com.qianda.qdminiapp.domain.data.OrderContextData;
import com.qianda.qdminiapp.domain.dto.OrderAndPayDto;
import com.qianda.qdminiapp.domain.model.device.Device;
import com.qianda.qdminiapp.domain.model.device.QqdDevice;
import com.qianda.qdminiapp.domain.model.device.QqdStore;
import com.qianda.qdminiapp.domain.model.order.Order;
import com.qianda.qdminiapp.common.exception.ExceptionCode;
import com.qianda.qdminiapp.common.exception.SimpleException;
import com.qianda.qdminiapp.domain.model.order.QqdOrderInfo;
import com.qianda.qdminiapp.domain.model.order.QqdOrderTowel;
import com.qianda.qdminiapp.domain.model.personmanage.QqdCompany;
import com.qianda.qdminiapp.domain.model.user.QqdUser;
import com.qianda.qdminiapp.service.CommondManager;
import com.qianda.qdminiapp.service.OrderAndPaymentStrategy;
import com.qianda.qdminiapp.service.protocols.DeviceProtocolsV1;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

/**
 * @ClassName AbstractOrderAndPay
 * @Author cw
 * @Date 2019/8/7 8:42
 * @Version 1.0
 */
public abstract class  AbstractOrderAndPay implements OrderAndPaymentStrategy {

    private static Logger LOGGER = LoggerFactory.getLogger(AbstractOrderAndPay.class);


    public QqdUserDao userDao;
    public QqdOrderInfoDao orderInfoDao;
    public QqdOrderTowelDao qqdOrderTowelDao;
    private CommondManager commondManager;
    public QqdDeviceDao deviceDao;
    public QqdStoreDao qqdStoreDao;
    public QqdAccountTradeDao qqdAccountTradeDao;
    public MsgProducer msgProducer;
    public QqdCompanyDao qqdCompanyDao;

    public AbstractOrderAndPay(QqdUserDao userDao, QqdOrderInfoDao orderInfoDao,
                               QqdOrderTowelDao qqdOrderTowelDao, CommondManager commondManager,
                               QqdDeviceDao deviceDao,QqdStoreDao qqdStoreDao,QqdAccountTradeDao qqdAccountTradeDao,
                               MsgProducer msgProducer,QqdCompanyDao qqdCompanyDao) {

        this.userDao = userDao;
        this.orderInfoDao = orderInfoDao;
        this.qqdOrderTowelDao = qqdOrderTowelDao;
        this.commondManager = commondManager;
        this.deviceDao = deviceDao;
        this.qqdStoreDao = qqdStoreDao;
        this.qqdAccountTradeDao = qqdAccountTradeDao;
        this.msgProducer = msgProducer;
        this.qqdCompanyDao  = qqdCompanyDao;
    }

    /*
     * 校验，判断状态
     * @Description
     * @Author cw
     * @Date 11:22 2019/8/7
     * @Param []
     * @return boolean
     **/
     public  abstract boolean checkStatus(OrderAndPayDto orderAndPayDto);

    /*
     * 公共校验部分
     * @Description
     * @Author cw
     * @Date 13:08 2019/8/7
     * @Param []
     * @return java.lang.Boolean
     **/
    public  QqdDevice CommonCheck(Long deviceId,String imei, Long userId, CompanyProperties companyProperties){

        if(imei == null){
            throw new SimpleException(ExceptionCode.EX_DEVICE_IMEI_NULL);
        }
        if(deviceId == null){
            throw new SimpleException(ExceptionCode.EX_DEVICE_IMEI_NULL);
        }
//        QueryWrapper<QqdDevice> qqdDeviceQueryWrapper = new QueryWrapper<>();
//        qqdDeviceQueryWrapper.eq("imei",imei).eq("status",CommonConstant.Status.STATUS_NORMAL);
        QqdDevice device = deviceDao.selectById(deviceId);


        //判断设备是否存在
        if(device == null ){
            throw new SimpleException(ExceptionCode.EX_DEVICE_NOT_EXISTS);
        }

        //判断设备是否在线
        if(device.getDeviceOnline() == null || device.getDeviceOnline() == CommonConstant.DeviceOnline.DEVICE_ONLINE_NO){
            throw new SimpleException(ExceptionCode.EX_DEVICE_NOT_ONLINE);
        }

        QqdStore qqdStore = qqdStoreDao.selectById(device.getStoreId());
        //判断门店是否存在
        if(qqdStore == null){
            throw new SimpleException(ExceptionCode.EX_STORENOT_EXISTS);
        }

        //判断门店是否为运营状态
        if(qqdStore.getStoreStatus() ==CommonConstant.StoreStatus.STORE_STATUS_WAIT || qqdStore.getStatus() != CommonConstant.Status.STATUS_NORMAL){
            throw new SimpleException(ExceptionCode.EX_STORENOT_NOT_WORK);
        }

        //判断设备是否为运营状态
        if(device.getDeviceStatus() != CommonConstant.DeviceStatus.DEVICE_STATUS_WORKING || device.getStatus() != CommonConstant.Status.STATUS_NORMAL){
            throw new SimpleException(ExceptionCode.EX_DEVICE_NOT_WORK);
        }

        //判断用户所在的公司与设备所属公司是否一致
        QqdUser qqdUser = userDao.selectById(userId);

        if(qqdUser.getStatus() == CommonConstant.Status.STATUS_BLOCKING){
            throw new SimpleException(ExceptionCode.EX_USER_BLOCKING);
        }

        if(!qqdUser.getCompanyId().equals(device.getCompanyId()) || !qqdUser.getCompanyId().equals(companyProperties.getId())){
         //   QqdCompany qqdCompany = qqdCompanyDao.selectById(device.getCompanyId());
          //  if(qqdCompany.getCompanyType() != CommonConstant.CompanyType.COMPANY_TYPE_PUB){
                throw new SimpleException(ExceptionCode.EX_DEVICE_BLONG_ERROR);
          //  }
        }
        QqdCompany qqdCompany = qqdCompanyDao.selectById(qqdUser.getCompanyId());
        if(qqdCompany.getStatus() != CommonConstant.Status.STATUS_NORMAL ){
            throw new SimpleException(ExceptionCode.EX_COMPANY_ERRROR);
        }
        return device;
    }

    /*
     *  设备自检
     * @Description
     * @Author cw
     * @Date 11:22 2019/8/7
     * @Param []
     * @return java.lang.Boolean
     **/
    public Boolean deviceStatusCheck(OrderAndPayDto orderAndPayDto,QqdDevice device){
            if(device.getDeviceProtocolsVersion() == CommonConstant.DeviceProtocolsVersion.DEVICE_PROTOCOLS_VERSION_NEW){
               return  protocoleNewCheck(orderAndPayDto,device);
            }else if(device.getDeviceProtocolsVersion() == CommonConstant.DeviceProtocolsVersion.DEVICE_PROTOCOLS_VERSION_OLD){
                return protocoleOldCheck(orderAndPayDto,device);
            }else{
                return true;
            }
       }

    /**
     * 老设备自检功能(设置毛巾长度)
     * @param orderAndPayDto
     * @param device
     * @return
     */
    private Boolean protocoleOldCheck(OrderAndPayDto orderAndPayDto,QqdDevice device) {
        SendData sendData = new SendData(null,1);
        sendData.put("command",1);
        sendData.put("imei",orderAndPayDto.getImei());
        sendData.put("protocolsV", device.getDeviceProtocolsVersion());
        sendData.put("towelLength",device.getDeviceLength());
        String futureId = orderAndPayDto.getImei();
        CommandFuture send = msgProducer.send(sendData, futureId, 10l);
        try{
            Map<String,Object> result = (Map<String, Object>) send.get(10l, TimeUnit.SECONDS);
            if(result != null){

                Integer status = Integer.valueOf(result.get("status").toString().trim());
               // Integer count =Integer.valueOf( result.get("count").toString().trim());

//                if(count< device.getDeviceLength( )* orderAndPayDto.getMjCount()){
//                    throw  new SimpleException(ExceptionCode.EX_DEVICE_COUNT_NOT_ENOUGH);
//                }
                //：00:正常/01:缺水/02:缺巾/03:卷巾处卡巾/04:切巾电机异常/05:切巾处卡巾/06:IC卡模块错误/07:卷巾余额不足；（2位）
                if(status == 0){
                    return true;
                }
//                else if(status == CommonConstant.DeviceErrorStatus.ORDER_ERROR_TYPE_1){
//                    //缺水
//                    throw new SimpleException(ExceptionCode.EX_DEVICE_STATUS_1);
//                }else if(status == CommonConstant.DeviceErrorStatus.ORDER_ERROR_TYPE_2){
//                    //缺巾
//                    throw new SimpleException(ExceptionCode.EX_DEVICE_STATUS_2);
//                }else if(status == CommonConstant.DeviceErrorStatus.ORDER_ERROR_TYPE_03){
//                    //卷巾处卡巾
//                    throw new SimpleException(ExceptionCode.EX_DEVICE_STATUS_3);
//                }else if(status == CommonConstant.DeviceErrorStatus.ORDER_ERROR_TYPE_4){
//                    //切巾电机异常
//                    throw new SimpleException(ExceptionCode.EX_DEVICE_STATUS_4);
//                }else if(status == CommonConstant.DeviceErrorStatus.ORDER_ERROR_TYPE_5){
//                    //切巾处卡巾
//                    throw new SimpleException(ExceptionCode.EX_DEVICE_STATUS_5);
//                }else if(status == CommonConstant.DeviceErrorStatus.ORDER_ERROR_TYPE_6){
//                    //IC卡模块错误
//                    throw new SimpleException(ExceptionCode.EX_DEVICE_STATUS_6);
//                }else if(status == CommonConstant.DeviceErrorStatus.ORDER_ERROR_TYPE_7){
//                    //卷巾余额不足
//                    throw new SimpleException(ExceptionCode.EX_DEVICE_COUNT_NOT_ENOUGH);
//                }
            }

        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        } catch (TimeoutException e) {
            e.printStackTrace();
        }
        throw new SimpleException(ExceptionCode.EX_DEVICE_SET_SELF_ERROR);

    }


        /**
         * 新设备自检功能
         * @param orderAndPayDto
         * @param device
         * @return
         */
    private Boolean protocoleNewCheck(OrderAndPayDto orderAndPayDto,QqdDevice device){
        SendData sendData = new SendData(null,2);
        sendData.put("command",2);
        sendData.put("imei",orderAndPayDto.getImei());
        String futureId = orderAndPayDto.getImei();
        CommandFuture send = msgProducer.send(sendData, futureId, 10l);
        try {//0H01|867881041240461|01|00005|00|25|.
            Map<String,Object> result = (Map<String, Object>) send.get(10l, TimeUnit.SECONDS);
            if(result != null){

                Integer status = Integer.valueOf(result.get("status").toString().trim());
                Integer count =Integer.valueOf( result.get("count").toString().trim());

                if(count< device.getDeviceLength( )* orderAndPayDto.getMjCount()){
                    throw  new SimpleException(ExceptionCode.EX_DEVICE_COUNT_NOT_ENOUGH);
                }
                //：00:正常/01:缺水/02:缺巾/03:卷巾处卡巾/04:切巾电机异常/05:切巾处卡巾/06:IC卡模块错误/07:卷巾余额不足；（2位）
                if(status == 0){
                    return true;
                }else if(status == CommonConstant.DeviceErrorStatus.ORDER_ERROR_TYPE_1){
                    //缺水
                    throw new SimpleException(ExceptionCode.EX_DEVICE_STATUS_1);
                }else if(status == CommonConstant.DeviceErrorStatus.ORDER_ERROR_TYPE_2){
                    //缺巾
                    throw new SimpleException(ExceptionCode.EX_DEVICE_STATUS_2);
                }else if(status == CommonConstant.DeviceErrorStatus.ORDER_ERROR_TYPE_03){
                    //卷巾处卡巾
                    throw new SimpleException(ExceptionCode.EX_DEVICE_STATUS_3);
                }else if(status == CommonConstant.DeviceErrorStatus.ORDER_ERROR_TYPE_4){
                    //切巾电机异常
                    throw new SimpleException(ExceptionCode.EX_DEVICE_STATUS_4);
                }else if(status == CommonConstant.DeviceErrorStatus.ORDER_ERROR_TYPE_5){
                    //切巾处卡巾
                    throw new SimpleException(ExceptionCode.EX_DEVICE_STATUS_5);
                }else if(status == CommonConstant.DeviceErrorStatus.ORDER_ERROR_TYPE_6){
                    //IC卡模块错误
                    throw new SimpleException(ExceptionCode.EX_DEVICE_STATUS_6);
                }else if(status == CommonConstant.DeviceErrorStatus.ORDER_ERROR_TYPE_7){
                    //卷巾余额不足
                    throw new SimpleException(ExceptionCode.EX_DEVICE_COUNT_NOT_ENOUGH);
                }
            }

        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        } catch (TimeoutException e) {
            e.printStackTrace();
        }
        throw new SimpleException(ExceptionCode.EX_DEVICE_CHECK_SELF_ERROR);

    }


    /*
     * 创建订单
     * @Description
     * @Author cw
     * @Date 11:23 2019/8/7
     * @Param []
     * @return com.qianda.qdminiapp.domain.model.order.Order
     **/
    public OrderContextData createOrder(OrderAndPayDto orderAndPayDto) throws Exception{
//        QueryWrapper<QqdDevice> qqdDeviceQueryWrapper = new QueryWrapper<>();
//        qqdDeviceQueryWrapper.eq("imei",orderAndPayDto.getImei()).eq("status",CommonConstant.Status.STATUS_NORMAL);
        QqdDevice device = deviceDao.selectById(orderAndPayDto.getDeviceId());
        if(device == null){
            throw new SimpleException(ExceptionCode.EX_DEVICE_NOT_EXISTS);
        }

        LOGGER.info("开始创建订单");
        String orderNo = RandomUtil.getId();
        //创建订单主表
        QqdOrderInfo qqdOrderInfo = new QqdOrderInfo();
        qqdOrderInfo.setOrderNo(orderNo);
        qqdOrderInfo.setOrderUserId(orderAndPayDto.getUserId());
        qqdOrderInfo.setOrderType(CommonConstant.QqdOrderType.QQD_ORDER_TYPE_BUY_TOWEL);
        qqdOrderInfo.setOrderTime(LocalDateTime.now());
        qqdOrderInfo.setOrderAmt(orderAndPayDto.getPayMoney());
        qqdOrderInfo.setOrderRealAmt(orderAndPayDto.getPayMoney());
        qqdOrderInfo.setStatus(CommonConstant.Status.STATUS_NORMAL);
        qqdOrderInfo.setCreateTime(LocalDateTime.now());
        orderInfoDao.insert(qqdOrderInfo);
        //创建订单子表
        QqdOrderTowel qqdOrderTowel = new QqdOrderTowel();
        qqdOrderTowel.setOrderNo(qqdOrderInfo.getOrderNo());
        qqdOrderTowel.setStoreId(device.getStoreId());
        qqdOrderTowel.setOrderCount(orderAndPayDto.getMjCount());
        qqdOrderTowel.setOrderId(qqdOrderInfo.getId());
        qqdOrderTowel.setOrderTowelType(device.getDeviceType());
        qqdOrderTowel.setOrderUserId(orderAndPayDto.getUserId());
        qqdOrderTowel.setOrderDeviceId(device.getId());
        qqdOrderTowel.setCompanyId(device.getCompanyId());
        qqdOrderTowel.setOrderAmt(orderAndPayDto.getPayMoney());
        qqdOrderTowel.setOrderStatus(CommonConstant.OrderOutTowelStatus.ORDER_OUT_TOWEL_STATUS_WAIT);
        qqdOrderTowel.setOrderDeviceLength(device.getDeviceLength());
        //qqdOrderTowel.setOrderTowelType(orderAndPayDto.getOrderTowelType());
        qqdOrderTowel.setOrderPayType(orderAndPayDto.getPayType());
        qqdOrderTowel.setStatus(CommonConstant.Status.STATUS_NORMAL);
        qqdOrderTowel.setOrderPayStatus(CommonConstant.PayStatus.PAY_STATUS_WAIT);
        qqdOrderTowel.setCreateTime(LocalDateTime.now());

        qqdOrderTowelDao.insert(qqdOrderTowel);
        LOGGER.info("订单创建完成");
        return new OrderContextData(qqdOrderTowel,qqdOrderInfo);
    }

    /*
     * 发起支付
     * @Description
     * @Author cw
     * @Date 11:23 2019/8/7
     * @Param [order]
     * @return void
     **/
    public  abstract  Map<String,Object> appPay(QqdOrderInfo qqdOrderInfo);

    /*
     * 出巾命令
     * @Description
     * @Author cw
     * @Date 11:23 2019/8/7
     * @Param []
     * @return void
     **/
    public  void startCommond(String orderId){
        commondManager.startCreateTowel(orderId);
    }


    /**
     * 计算该笔交易金额及出巾数量
     *
     * @return
     * @throws Exception
     * @author wangShuqi
     * @serialData 2019/06/20
     */
    public  Map<String, Object> arithPayMoney(Integer mjCount,Device device)  {
        Map<String, Object> resultMap = new HashMap<String, Object>();

        // 单条毛巾金额
        BigDecimal priceForOne =  device.getDevicePrice();

        // 交易毛巾数量
        Integer towelCount = null;
        if (mjCount == null) {// 如果mj数量为空，则取设备设定的毛巾数量
            towelCount = device.getOutputCount();
            LOGGER.info("设备每次出巾数量为：" + towelCount + "条");
            if (towelCount == null || towelCount <= 1) {
                towelCount = 1;
            }
        } else {
            towelCount = mjCount;
        }
        resultMap.put("towelCount", towelCount);
        resultMap.put("payMoney", BigDecimal.valueOf(towelCount).multiply(priceForOne).setScale(2,BigDecimal.ROUND_HALF_UP));
        return resultMap;
    }

    /*
     * 发起退款
     * @Description
     * @Author cw
     * @Date 11:49 2019/8/9
     * @Param [order]
     * @return void
     **/
    public  abstract  void refundPay(QqdOrderTowel order);


}
